package network

import (
	"net"
	"github.com/wanhuo/GoSocketFrame/common"
	"sync"
	"github.com/wanhuo/GoSocketFrame/utils"
	"github.com/gorilla/websocket"
	"net/http"
	"net/url"
	"errors"
	"time"
)

type WebSocketAcceptor struct {
	listener       net.Listener
	running        bool
	sockMap        map[uint64]*WebSession
	fdcounter      uint64
	iattemper      common.IAttemperEngineSink
	mutex          sync.Mutex
	keepAliveTimer *utils.Timer  //心跳定时器
	log            *utils.Logger //日志句柄
	certfile 	   string
	keyfile        string
}


var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
} // use default options


func (self *WebSocketAcceptor) SetHttps(certfile, keyfile string) {
	self.certfile = certfile
	self.keyfile = keyfile
}


func (self *WebSocketAcceptor) Start(address string, keepAliveStatus NetworkStatus) error {
	if self.running {
		return nil
	}
	self.sockMap = make(map[uint64]*WebSession)
	self.running = true
	//与客户端的连接需要心跳 需要加密
	if keepAliveStatus != NetworkStatus_Normal {
		if self.keepAliveTimer == nil {
			self.keepAliveTimer = utils.NewTimer(self, KEEPALIVE_DETECT_TIME*time.Second, 0)
			self.keepAliveTimer.Start(utils.Timer_RunLoop)
		}
	}

	urlObj, err := url.Parse(address)

	if err != nil {
		self.log.Errorf("#websocket.urlparse failed(%s) %v", address ,err.Error())
		return err
	}

	if urlObj.Path == "" {
		self.log.Errorf("#websocket start failed, expect path in url to listen")
		return errors.New("urlObj.Path is null")
	}

	mux := http.NewServeMux()

	mux.HandleFunc(urlObj.Path, func(w http.ResponseWriter, r *http.Request) {
		conn, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			self.log.Debugln(err)
			return
		}
		self.mutex.Lock()
		self.fdcounter++
		ses := NewWebSession(self.fdcounter, conn, self.iattemper)
		self.sockMap[self.fdcounter] = ses
		self.mutex.Unlock()
		self.iattemper.OnEventTCPNetworkLink(ses)
		ses.OnClose = func(ises common.ISession) {
			self.mutex.Lock()
			delete(self.sockMap, ises.ID())
			self.mutex.Unlock()
			self.log.Debugf("[关闭连接] ses:%d\n", ses.ID())
		}

		ses.SetBindData(KeepAlive_Safe)
		self.log.Debugf("[新的连接] ses:%d\n", ses.ID())
	})

	self.log.Infof("#websocket.listen (%s)", address)
	if urlObj.Scheme == "https" {
		err = http.ListenAndServeTLS(urlObj.Host, self.certfile, self.keyfile, mux)
	} else {
		err = http.ListenAndServe(urlObj.Host, mux)
	}
	if err != nil {
		self.log.Errorf("#websocket.listen. failed %v", err.Error())
	}
	return nil
	
}

func (self *WebSocketAcceptor) OnTimer(callback int) {
	var deadSesVec []*WebSession
	self.mutex.Lock()
	//fmt.Println(time.Now().Unix())
	//遍历所有session
	for i := range self.sockMap {
		ses := self.sockMap[i]
		if ses == nil {
			continue
		}
		userData := ses.GetBindData()
		switch status := userData.(type) {
		case ConnectStatusType:
			if status == KeepAlive_Dead {
				deadSesVec = append(deadSesVec, ses)
			} else if status == KeepAlive_Safe {
				status--
				ses.SetBindData(status)
			} else if status == KeepAlive_Warn {
				status--
				ses.SetBindData(status)
				//这里需要加入心跳检测的命令
				ses.Send(MainCmd_Network_FrameWork, SubCmd_Network_HeartBeat, nil)
			}
		}
	}
	self.mutex.Unlock()
	for _, ses := range deadSesVec {
		self.iattemper.OnEventTCPNetworkShut(ses)
		if ses.OnClose != nil {
			ses.OnClose(ses)
		}
	}
}

func (self *WebSocketAcceptor) Stop() {
	if !self.running {
		return
	}
	self.running = false
}

func NewWebAcceptor(attemper common.IAttemperEngineSink) *WebSocketAcceptor {
	self := &WebSocketAcceptor{
		iattemper: attemper,
		fdcounter: 0,
		log:       utils.NewLogger(),
	}

	return self
}
